package vsm.vsm_server.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import vsm.vsm_server.mapper.CFMapper;
import vsm.vsm_server.pojo.CF.User_User_CF;
import vsm.vsm_server.pojo.CF.User_Video_CF;
import vsm.vsm_server.pojo.CF.Video_Video_CF;
import vsm.vsm_server.pojo.User.Record.History.UserVideoHistoryDTO;
import vsm.vsm_server.pojo.User.Record.Like.UserVideoIsLikeDTO;
import vsm.vsm_server.pojo.Video.UserVideoPair;
import vsm.vsm_server.service.CFService;
import vsm.vsm_server.service.HistoryService;
import vsm.vsm_server.service.LikeService;

import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CFServiceImpl implements CFService {
    private CFMapper cfMapper;

    public  CFServiceImpl(CFMapper cfMapper){this.cfMapper=cfMapper;}

     @Autowired
    HistoryService historyService;
    @Autowired
    LikeService likeService;
    @Override
    public List<User_Video_CF> getUserInterest(BigInteger userId,int count) {
        return cfMapper.getUserInterest(userId,count);
    }

    @Override
    public List<Video_Video_CF> getItemSim(BigInteger videoId,int count) {
        return cfMapper.getItemSim(videoId,count);
    }

    @Override
    public List<User_User_CF> getUserSim(BigInteger userId,int count) {
        return cfMapper.getUserSim(userId,count);
    }


    @Override
    public void calUserVideoInterest() {
       int HISTORY_LIMIT_PER_USER = 100;
       int BATCH_WRITE_SIZE = 1000;
       double LIKE_WEIGHT = 4.0; // 点赞的权重 (可调)
       double FINISHED_WEIGHT = 1.0; // 观看完成度的权重 (可调)
        log.info("Starting task to calculate user-video interest based on history and likes...");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        LocalDateTime updateTime = LocalDateTime.now();

        // 1. 获取每个用户最新的 N 条观看历史
        //    假设 historyService.getAllHistoryVideos 返回 List<UserVideoHistoryDto>
        //    并且 UserVideoHistoryDto 包含 getUserId(), getVideoId(), getFinished()
        log.debug("Fetching recent history for all users...");
        List<UserVideoHistoryDTO> historyList = historyService.getAllHistoryVideos(HISTORY_LIMIT_PER_USER);
        if (historyList == null || historyList.isEmpty()) {
            log.info("No recent history found.");
            return;
        }
        log.debug("Fetched {} history records.", historyList.size());

        // 2. 批量检查这些历史记录对应的点赞状态
        //    假设 likeService.isLikeVideoList 返回 List<UserVideoIsLikeDTO>
        //    并且 UserVideoIsLikeDTO 包含 getUserId(), getVideoId(), isLike()
        log.debug("Checking like status for history records...");
        List<UserVideoIsLikeDTO> likeList = likeService.isLikeVideoList(historyList); // <--- 改回 UserVideoIsLikeDTO
        log.info("likeList:{}",likeList);
        if (likeList == null) likeList = Collections.emptyList();
        log.debug("Checked like status, found {} like info records.", likeList.size());

// --- *** 构建 Map，处理 Boolean isLike *** ---
        Map<UserVideoPair, Boolean> likeMap = likeList.stream()
                .filter(dto -> dto != null && dto.getUserId() != null && dto.getVideoId() != null)
                .collect(Collectors.toMap(
                        dto -> new UserVideoPair(dto.getUserId(), dto.getVideoId()),
                        // --- *** 正确处理 Boolean isLike *** ---
                        dto -> {
                            Boolean likeStatus = dto.getIsLike(); // 调用 getter
                            return likeStatus != null && likeStatus; // 只有明确为 true 才返回 true, null 或 false 都返回 false
                        },
                        (existing, replacement) -> replacement
                ));
        log.debug("Created likeMap with {} entries.", likeMap.size());


        // 4. 准备批量写入的列表
        List<User_Video_CF> interestToSave = new ArrayList<>();

        // 5. 遍历历史记录，计算兴趣度并添加到列表
        log.debug("Calculating interest scores...");
        for (UserVideoHistoryDTO historyDto : historyList) {
            if (historyDto == null || historyDto.getUserId() == null || historyDto.getVideoId() == null) {
                continue; // 跳过无效历史记录
            }

            BigInteger userId = historyDto.getUserId();
            BigInteger videoId = historyDto.getVideoId();

            // 创建查找 Key
            UserVideoPair key = new UserVideoPair(userId, videoId);

            // 获取点赞状态 (默认 false)
            boolean isLiked = likeMap.getOrDefault(key, false);
            double isLikeScore = isLiked ? 1.0 : 0.0; // 转换为分数

            // 获取观看完成度分数 (需要确认 getFinished 返回值的含义和范围)
            // 假设 getFinished 返回的是 0 到 1 之间的比例，如果不是，需要调整
            double finishedScore = (historyDto.getFinished() != null) ?
                    Math.max(0.0, Math.min(1.0, historyDto.getFinished())) // 裁剪到 [0,1]
                    : 0.0; // 如果 finished 为 null，算 0 分


            // 计算综合兴趣度 (使用加权方式)
            double interest = (LIKE_WEIGHT * isLikeScore) + (FINISHED_WEIGHT * finishedScore);
            // 可以增加其他逻辑，比如至少要观看一点才算分，或者点赞权重更高

            // 只有当计算出的兴趣度大于 0 才保存 (避免存大量 0 分记录)
            if (interest > 1e-6) { // 使用小的 epsilon 比较浮点数
                User_Video_CF userVideoCf = new User_Video_CF();
                userVideoCf.setUserId(userId);
                userVideoCf.setToVideoId(videoId);
                userVideoCf.setInterest(interest);

                userVideoCf.setUpdateTime(updateTime);
                // --- *** 不要在这里保存，先添加到列表 *** ---
                interestToSave.add(userVideoCf);
            }
        }
        log.debug("Calculated {} user-video interest records to save.", interestToSave.size());


        // 6. 批量写入/更新数据库
        if (!interestToSave.isEmpty()) {
            log.info("Saving/Updating {} user-video interest records in batches...", interestToSave.size());
            for (User_Video_CF userVideoCf:interestToSave) {
                cfMapper.saveUserVideoCF(userVideoCf);
            }
            log.info("Finished saving user-video interest records.");
        } else {
            log.info("No user-video interest records needed saving in this run.");
        }
        log.info("User-video interest calculation task finished.");
    }


    @Value("${python.api.url.calSim}") // 确保配置文件中有 python.api.url
    private String pythonApiUrl;
    @Autowired // 注入 RestTemplate Bean
    private RestTemplate restTemplate;
    @Override
    public void calSim() {
        Map<String, Object> requestBody = new HashMap<>();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);

        ResponseEntity<String> responseEntity;
        try {
           //log.debug("Sending {} instances to prediction service at {}", instances.size(), pythonApiUrl);
            responseEntity = restTemplate.postForEntity(pythonApiUrl, requestEntity, String.class);
        } catch (RestClientException e) {
            log.error("Error calling prediction service at {}: {}", pythonApiUrl, e.getMessage(), e);
        }

    }




    @Override
    @Scheduled(cron = "0 0/20 * * * ?") // 定时任务注解保留在方法上
    @Async // 异步执行注解保留在方法上
    public void saveCF() {
        log.info("保存召回信息");
        calUserVideoInterest();
        calSim();

    }
}
